package com.oss.service.oss;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.oss.dto.oss.capitalsummary.CapitalSummaryImportDetailDto;
import com.oss.dto.oss.capitalsummary.CapitalSummaryImportDto;
import com.oss.dto.oss.capitalsummary.PageDto;
import com.oss.dto.oss.positionmanage.CountDto;
import com.oss.entity.oss.CapitalManage;
import com.oss.entity.oss.CapitalSummary;
import com.oss.enums.IsDeletedEnum;
import com.oss.mapper.oss.CapitalSummaryMapper;
import com.oss.service.system.UserService;
import com.oss.util.SnowFlakeUtil;
import com.oss.vo.oss.capitalsummary.CapitalSummaryAndInOutDetailVO;
import com.oss.vo.oss.capitalsummary.CapitalSummaryDetailVO;
import com.oss.vo.oss.capitalsummary.CapitalSummaryOrgDataVO;
import com.oss.vo.oss.capitalsummary.CapitalSummaryVO;
import com.oss.vo.oss.position.PositionManageVO;
import com.oss.vo.oss.student.StudentVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class CapitalSummaryService extends ServiceImpl<CapitalSummaryMapper, CapitalSummary> {

    @Autowired
    StudentService studentService;
    @Autowired
    UserService userService;
    @Autowired
    CapitalManageService capitalManageService;
    @Autowired
    PositionManageService positionManageService;

    public IPage<CapitalSummaryOrgDataVO> selectByPageOrgData(PageDto dto) {
        LambdaQueryWrapper<CapitalSummary> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CapitalSummary::getIsDeleted, IsDeletedEnum.NO.getFlag());
        wrapper.eq(StringUtils.isNotBlank(dto.getStudentID()),CapitalSummary::getStudentID,dto.getStudentID());
        wrapper.eq(dto.getOccurrenceDate() != null,CapitalSummary::getOccurrenceDate,dto.getOccurrenceDate());

        IPage<CapitalSummary> page = this.page(new Page<>(dto.getPageNo(), dto.getPageSize()), wrapper);
        Map<String, StudentVO> studentMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(page.getRecords())){
            Set<String> ids = page.getRecords().stream().map(CapitalSummary::getStudentID).collect(Collectors.toSet());
            studentMap = studentService.selectByIDs(ids);
        }
        Map<String, StudentVO> finalStudentMap = studentMap;
        Map<String,String> userMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(page.getRecords())) {
            // 获取创建人和修改人ID
            Set<String> ids = page.getRecords().stream().map(CapitalSummary::getCreatorId).collect(Collectors.toSet());
            ids.addAll(page.getRecords().stream().map(CapitalSummary::getUpdatorId).collect(Collectors.toSet()));
            userMap = userService.selectByIds(ids);
        }
        Map<String, String> finalUserMap = userMap;
        return page.convert(entity->{
            CapitalSummaryOrgDataVO vo = new CapitalSummaryOrgDataVO();
            BeanUtils.copyProperties(entity,vo);
            if (finalStudentMap.containsKey(entity.getStudentID())){
                StudentVO studentVO = finalStudentMap.get(entity.getStudentID());
                vo.setStudentID(studentVO.getId());
                vo.setStudentAccount(studentVO.getAccount());
            }
            vo.setCreatorName(finalUserMap.get(entity.getCreatorId()));
            vo.setUpdatorName(finalUserMap.get(entity.getUpdatorId()));
            return vo;
        });
    }


    /**
     * 根据学员ID, 发生日期(只查询外部推送的)
     * @param studentID
     * @param occurrenceDate
     * @return
     */
    public void deleteByStudentIDAndDate(String studentID, LocalDate occurrenceDate) {
        LambdaUpdateWrapper<CapitalSummary> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(CapitalSummary::getIsDeleted, IsDeletedEnum.NO.getFlag());
        wrapper.eq(CapitalSummary::getStudentID,studentID);
        wrapper.eq(CapitalSummary::getOccurrenceDate,occurrenceDate);
        wrapper.eq(CapitalSummary::getDataSource,0);
        wrapper.set(CapitalSummary::getIsDeleted,IsDeletedEnum.YES.getFlag());
        this.update(null,wrapper);
    }


    public String importData(CapitalSummaryImportDto dto) {
        List<CapitalSummary> addList = new ArrayList<>();
        Set<String> accountSet = dto.getList().stream().map(CapitalSummaryImportDetailDto::getAccount).collect(Collectors.toSet());
        Map<String, String> studentAccountMap = studentService.getByAccountSet(accountSet);
        for (CapitalSummaryImportDetailDto item : dto.getList()) {
            if (studentAccountMap.containsKey(item.getAccount())) {
                String studentID = studentAccountMap.get(item.getAccount());
                deleteByStudentIDAndDate(studentID,item.getOccurrenceDate());
                // 插入
                CapitalSummary entity = new CapitalSummary();
                BeanUtils.copyProperties(item,entity);
                entity.setStudentID(studentID);
                entity.setId(SnowFlakeUtil.getID());
                entity.setCreatorId("-1");
                addList.add(entity);
            } else {
                log.warn(item.getAccount()+"此账号对应的学员不存在; "+ "需要插入的数据="+ JSON.toJSONString(item));
            }
        }
        if (CollectionUtils.isNotEmpty(addList)){
            this.saveBatch(addList);
        }
        return "操作成功";
    }

    /**
     * 按学员ID和日期及分组统计
     * @param dto
     * @return
     */
    public List<CapitalSummaryVO> capitalSummary(PageDto dto) {
        List<CapitalSummaryVO> returnList = new ArrayList<>();
        LambdaQueryWrapper<CapitalSummary> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CapitalSummary::getIsDeleted, IsDeletedEnum.NO.getFlag());
        wrapper.eq(StringUtils.isNotBlank(dto.getStudentID()),CapitalSummary::getStudentID,dto.getStudentID());
        wrapper.eq(dto.getOccurrenceDate() != null,CapitalSummary::getOccurrenceDate,dto.getOccurrenceDate());
        // 资金汇总原始数据
        List<CapitalSummary> list = this.list(wrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            Set<String> ids = list.stream().map(CapitalSummary::getStudentID).collect(Collectors.toSet());
            // 根据学员ID查询资金列表
            List<CapitalManage> capitalList = capitalManageService.selectByStudentIdSet(ids);
            // 按账号分组
            Map<String,List<CapitalSummary>> sidMap = list.stream().collect(Collectors.groupingBy(CapitalSummary::getStudentID));
            for (Map.Entry<String, List<CapitalSummary>> entry : sidMap.entrySet()) {
                String studentID = entry.getKey();
                List<CapitalSummary> sidList = entry.getValue();
                // 按发生日期分组
                Map<LocalDate,List<CapitalSummary>> occurrenceDateMap = sidList.stream().collect(Collectors.groupingBy(CapitalSummary::getOccurrenceDate));
                for (Map.Entry<LocalDate, List<CapitalSummary>> occurrenceDateEntry : occurrenceDateMap.entrySet()) {
                    LocalDate occurrenceDate = occurrenceDateEntry.getKey();
                    List<CapitalSummary> sameDateList = occurrenceDateEntry.getValue();
                    if (CollectionUtils.isNotEmpty(sameDateList)) {
                        BigDecimal sameDateCount = new BigDecimal(sameDateList.size());
                        CapitalSummaryVO vo = new CapitalSummaryVO();
                        vo.setStudentID(studentID);
                        vo.setOccurrenceDate(occurrenceDate);
                        // 可用资金
                        vo.setAvailableAmount(sameDateList.stream().map(item->item.getAvailableAmount()==null?BigDecimal.ZERO:item.getAvailableAmount()).reduce(BigDecimal.ZERO, BigDecimal::add).divide(sameDateCount,BigDecimal.ROUND_HALF_UP));
                        // 保证金占用
                        vo.setMarginOccupy(sameDateList.stream().map(item->item.getMarginOccupy()==null?BigDecimal.ZERO:item.getMarginOccupy()).reduce(BigDecimal.ZERO, BigDecimal::add).divide(sameDateCount,BigDecimal.ROUND_HALF_UP));
                        // 风险度
                        vo.setRiskExposure(sameDateList.stream().map(item->{
                            return new BigDecimal(item.getRiskExposure().replace("%",""));
                        }).reduce(BigDecimal.ZERO, BigDecimal::add).divide(sameDateCount,BigDecimal.ROUND_HALF_UP));

                        // 某个学员账号的资金记录
                        List<CapitalManage> studentCapitalList = capitalList.stream().filter(item->item.getStudentID().equals(studentID)).collect(Collectors.toList());
                        // 初始本金(一个学员只有一条记录)
                        List<CapitalManage> initCapitalList = studentCapitalList.stream().filter(item->40==item.getInoutFlag()).collect(Collectors.toList());
                        BigDecimal initCapital = CollectionUtils.isEmpty(initCapitalList) ? BigDecimal.ZERO : initCapitalList.stream().findFirst().get().getAmount();
                        // 预防值为null
                        initCapital = initCapital == null ? BigDecimal.ZERO : initCapital;
                        // 增加本金(统计所有日期的)
                        BigDecimal addCapital = studentCapitalList.stream().filter(item->item.getInoutFlag()==41)
                                .map(item->item.getAmount()==null?BigDecimal.ZERO:item.getAmount()).reduce(BigDecimal.ZERO, BigDecimal::add);
                        // 预防值为null
                        addCapital = addCapital == null ? BigDecimal.ZERO : addCapital;
                        // 减少本金(统计所有日期的)
                        BigDecimal subtractCapital = studentCapitalList.stream().filter(item->item.getInoutFlag()==42)
                                .map(item->item.getAmount()==null?BigDecimal.ZERO:item.getAmount()).reduce(BigDecimal.ZERO, BigDecimal::add);
                        subtractCapital = subtractCapital == null ? BigDecimal.ZERO : subtractCapital;
                        // 统计全部资金记录资金类型=出金或入金
                        List<CapitalManage> dateList = studentCapitalList.stream().filter(item->(item.getInoutFlag()==0 || item.getInoutFlag()==1)).collect(Collectors.toList());
                        // 出入金总额
                        BigDecimal inoutTotal = dateList.stream().map(item->item.getAmount()==null?BigDecimal.ZERO:item.getAmount()).reduce(BigDecimal.ZERO, BigDecimal::add);
                        // 预防值为null
                        inoutTotal = inoutTotal == null ? BigDecimal.ZERO : inoutTotal;
                        // 历史入金总额
                        BigDecimal historyDepositTotal = studentCapitalList.stream().filter(item->item.getInoutFlag()==1)
                                .map(item->item.getAmount()==null?BigDecimal.ZERO:item.getAmount()).reduce(BigDecimal.ZERO, BigDecimal::add);
                        BigDecimal historyWithdrawTotal = studentCapitalList.stream().filter(item->item.getInoutFlag()==0)
                                .map(item->item.getAmount()==null?BigDecimal.ZERO:item.getAmount()).reduce(BigDecimal.ZERO, BigDecimal::add);
                        // 期初权益 = 初始本金+出入金(资金管理中的 , 出金-入金)
                        vo.setPreviousDayBalance(initCapital.add(inoutTotal));
                        // 本金规模=初始本金+增加本金-减少本金
                        vo.setPrincipalScale(initCapital.add(addCapital).subtract(subtractCapital));
                        // 历史入金总额
                        vo.setHistoryDepositTotal(historyDepositTotal);
                        vo.setHistoryWithdrawTotal(historyWithdrawTotal);
                        CountDto countDto = new CountDto();
                        countDto.setStudentIDs(Arrays.asList(studentID));
                        countDto.setPositionDate(occurrenceDate);
                        // 只查询一天的持仓信息
                        List<PositionManageVO> positionList = positionManageService.countByList(countDto);
                        // 汇总这个学员的这一天的持仓市值
                        BigDecimal availableAmount = positionList.stream().map(item->item.getAvailableAmount()==null?BigDecimal.ZERO:item.getAvailableAmount()).reduce(BigDecimal.ZERO, BigDecimal::add);
                        availableAmount = availableAmount == null ? BigDecimal.ZERO : availableAmount;
                        // 持仓市值
                        vo.setPositionValue(availableAmount);
                        returnList.add(vo);
                    }
                }
            }
            if (CollectionUtils.isNotEmpty(returnList)) {
                Map<String, StudentVO> studentMap = studentService.selectByIDs(ids);
                returnList.stream().forEach(vo->{
                    if (studentMap.containsKey(vo.getStudentID())){
                        StudentVO studentVO = studentMap.get(vo.getStudentID());
                        vo.setStudentID(studentVO.getId());
                        vo.setStudentPhone(studentVO.getPhone());
                        vo.setStudentName(studentVO.getName());
                        vo.setStudentWechatID(studentVO.getWechatID());
                        vo.setStudentAccount(studentVO.getAccount());
                    }
                });
            }
            return returnList;
        } else {
            return new ArrayList<>();
        }
    }

    public CapitalSummaryAndInOutDetailVO getDetailById(String id) {
        CapitalSummaryAndInOutDetailVO vo = new CapitalSummaryAndInOutDetailVO();
        List<CapitalSummaryDetailVO> capitalSummaryDetailVOList = new ArrayList<>();
        CapitalSummary entity = this.getById(id);
        LambdaQueryWrapper<CapitalManage> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CapitalManage::getIsDeleted, IsDeletedEnum.NO.getFlag());
        wrapper.in(CapitalManage::getInoutFlag, Arrays.asList(0,1));
        wrapper.eq(CapitalManage::getStudentID, entity.getStudentID());
        List<CapitalManage> capitalManagelist = capitalManageService.list(wrapper);
        BeanUtils.copyProperties(entity,vo);
        for (CapitalManage item : capitalManagelist) {
            CapitalSummaryDetailVO detailVO = new CapitalSummaryDetailVO();
            detailVO.setOccurrenceDate(item.getTradeDate());
            detailVO.setMethod(item.getRemark());
            Integer inoutFlag = item.getInoutFlag();
            if (0 == inoutFlag) {
                detailVO.setWithdraw(item.getAmount());
                detailVO.setDeposit(BigDecimal.ZERO);
            } else if (1 == inoutFlag) {
                detailVO.setDeposit(item.getAmount());
                detailVO.setWithdraw(BigDecimal.ZERO);
            }
            capitalSummaryDetailVOList.add(detailVO);
        }
        vo.setList(capitalSummaryDetailVOList);
        return vo;
    }
}